<template>
  <t-space align="center">
    <t-button theme="primary" @click="visible = true">AI助手悬窗展示</t-button>
  </t-space>
  <t-drawer
    v-model:visible="visible"
    :footer="false"
    size="480px"
    :close-btn="true"
    class="drawer-box"
  >
    <template #header>
      <t-avatar
        size="32px"
        shape="circle"
        image="https://tdesign.gtimg.com/site/chat-avatar.png"
      ></t-avatar>
      <span class="title">Hi, &nbsp;我是AI</span>
    </template>
    <t-chat
      ref="chatRef"
      :clear-history="chatList.length > 0 && !isStreamLoad"
      :data="chatList"
      :text-loading="loading"
      :is-stream-load="isStreamLoad"
      @scroll="handleChatScroll"
      @clear="clearConfirm"
    >
    <template #content="{ item, index }">
        <t-chat-reasoning
          v-if="item.reasoning?.length > 0"
          expand-icon-placement="right"
        >
          <template #header>
            <t-chat-loading v-if="isStreamLoad" text="思考中..." indicator />
            <div v-else style="display: flex; align-items: center">
              <CheckCircleIcon
                style="
                  color: var(--td-success-color-5);
                  font-size: 20px;
                  margin-right: 8px;
                "
              />
              <span>已深度思考</span>
            </div>
          </template>
          <t-chat-content
            v-if="item.reasoning.length > 0"
            :content="item.reasoning"
          />
        </t-chat-reasoning>
        <t-chat-content
          v-if="item.content.length > 0"
          :content="item.content"
        />
      </template>
      <template #actions="{ item, index }">
        <t-chat-action
          :content="item.content"
          :operation-btn="['good', 'bad', 'replay', 'copy']"
          @operation="handleOperation"
        />
      </template>
      <template #footer>
        <t-chat-input
          :stop-disabled="isStreamLoad"
          @send="inputEnter"
          @stop="onStop"
        >
        </t-chat-input>
      </template>
    </t-chat>
    <t-button
      v-show="isShowToBottom"
      variant="text"
      class="bottomBtn"
      @click="backBottom"
    >
      <div class="to-bottom">
        <ArrowDownIcon />
      </div>
    </t-button>
  </t-drawer>
</template>
<script setup>
import { fetchEventSource } from "@microsoft/fetch-event-source";
import { ref } from "vue";
const visible = ref(false);
import { CheckCircleIcon, ArrowDownIcon } from "tdesign-icons-vue-next";

const fetchController = ref(null);
const chatRef = ref(null);
const loading = ref(false);
const isStreamLoad = ref(false);

const isShowToBottom = ref(false);

// 滚动到底部
const backBottom = () => {
  chatRef.value.scrollToBottom({
    behavior: "smooth",
  });
};
// 是否显示回到底部按钮
const handleChatScroll = function ({ e }) {
  const scrollTop = e.target.scrollTop;
  isShowToBottom.value = scrollTop < 0;
};

const handleOperation = function (type, options) {
  console.log('handleOperation', type, options);
};
// 倒序渲染
const chatList = ref([
  {
    avatar: "https://tdesign.gtimg.com/site/chat-avatar.png",
    role: "assistant",
    name: "AI小助手",
    content: "你好！我是AI小助手，有什么可以帮您的吗？",
    datetime: new Date().toDateString(),
  },
]);

const clearConfirm = function () {
  chatList.value = [];
};
const onStop = () => {
  console.log("停止",fetchController.value);
  if (fetchController.value) {
    fetchController.value.abort('手动取消')
    loading.value = false;
    isStreamLoad.value = false;
  }
};
const inputEnter = function (inputValue) {
  if (isStreamLoad.value) {
    return;
  }
  if (!inputValue) return;
  const params = {
    avatar: "https://tdesign.gtimg.com/site/avatar.jpg",
    name: "你",
    content: inputValue,
    role: "user",
    datetime: new Date().toDateString(),
  };
  chatList.value.unshift(params);
  // 空消息占位
  const params2 = {
    avatar: "https://tdesign.gtimg.com/site/chat-avatar.png",
    name: "AI小助手",
    content: "",
    reasoning: "",
    role: "assistant",
    datetime: new Date().toDateString(),
  };
  chatList.value.unshift(params2);
  fetchAIResponse(inputValue);
};

// 调用硅基流动的接口
const fetchAIResponse = async (inputValue) => {
  // 用于主动取消异步操作
  fetchController.value = new AbortController();
  // 流式加载是否结束
  isStreamLoad.value = true;
  // 聊天列表里的最有一个元素
  const lastItem = chatList.value[0];
  fetchEventSource("https://api.siliconflow.cn/v1/chat/completions", {
    method: "POST",
    headers: {
      Authorization:
        "Bearer sk-你的密钥",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      model: "deepseek-ai/DeepSeek-R1-Distill-Qwen-7B",
      messages: [
        {
          role: "user",
          content: inputValue,
        },
      ],
      // 开启流式
      stream: true,
    }),
    // 中断请求关联信号
    signal:fetchController.value.signal,
    onmessage(rsp) {
      console.log("【sse】Message from server:", rsp);
      // 流式响应或任务执行的结束标志
      if (rsp?.data === "[DONE]") {
        //lastItem.content += rsp?.data;
        loading.value = false;
        isStreamLoad.value = false;
        return;
      }
      // 将json转换成对象
      const data = JSON.parse(rsp?.data);
      // 获取内部的数据
      if (data.choices[0].delta.reasoning_content) {
        lastItem.reasoning += data.choices[0].delta.reasoning_content;
      } else if (data.choices[0].delta.content) {
        lastItem.content += data.choices[0].delta.content;
      }
    },
    onerror(err) {
      lastItem.content = `请求出错: ${err.message}`;
      fetchController.value.abort(err.message);
    },
  });
};
</script>
<style lang="less">
/* 应用滚动条样式 */
::-webkit-scrollbar-thumb {
  background-color: var(--td-scrollbar-color);
}
::-webkit-scrollbar-thumb:horizontal:hover {
  background-color: var(--td-scrollbar-hover-color);
}
::-webkit-scrollbar-track {
  background-color: var(--td-scroll-track-color);
}
.bottomBtn {
    position: absolute;
    left: 50%;
    margin-left: -20px;
    bottom: 210px;
    padding: 0;
    border: 0;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    box-shadow: 0px 8px 10px -5px rgba(0, 0, 0, 0.08), 0px 16px 24px 2px rgba(0, 0, 0, 0.04),
      0px 6px 30px 5px rgba(0, 0, 0, 0.05);
  }
  .to-bottom {
    width: 40px;
    height: 40px;
    border: 1px solid #dcdcdc;
    box-sizing: border-box;
    background: var(--td-bg-color-container);
    border-radius: 50%;
    font-size: 24px;
    line-height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    .t-icon {
      font-size: 24px;
    }
  }
</style>
